package com.lyf.auth.dataDao.impl;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.lyf.auth.dao.BindClientScopeMapper;
import com.lyf.auth.dao.ClientInfoMapper;
import com.lyf.auth.dao.JwkInfoMapper;
import com.lyf.auth.dao.ScopeApilistInfoMapper;
import com.lyf.auth.dataDao.AuthConfigurationDao;
import com.lyf.auth.domain.pojo.AuthConfiguration;
import com.lyf.auth.domain.pojo.Bean.BindClientScope;
import com.lyf.auth.domain.pojo.Bean.ClientInfo;
import com.lyf.auth.domain.pojo.Bean.JwkInfo;
import com.lyf.auth.domain.pojo.Bean.ScopeApilistInfo;
import com.lyf.auth.domain.pojo.JWKInfo;
import com.lyf.auth.domain.pojo.JwksInfo;
import com.lyf.auth.domain.pojo.ScopeSupportApiListAccess;
import com.lyf.auth.utils.UUIDUtil;
import com.lyf.common.exception.ApiException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component
public class AuthConfigurationDaoImpl implements AuthConfigurationDao {
   private static final Logger logger = LoggerFactory.getLogger(AuthConfigurationDaoImpl.class);
   @Autowired
   private RedisTemplate redisTemplate;
   @Resource
   private ClientInfoMapper clientInfoMapper;
   @Resource
   private BindClientScopeMapper bindClientScopeMapper;
   @Resource
   private ScopeApilistInfoMapper scopeApilistInfoMapper;
   @Resource
   private JwkInfoMapper jwkInfoMapper;
   private static final Long REDIS_TIMEOUT = 60L;
   private static final TimeUnit REDIS_TIMEOUT_UNIT;

   @Override
   public AuthConfiguration registerClientAccount(String comment, Set<String> owner)  {
      AuthConfiguration authConfiguration = new AuthConfiguration();
      String clientSecret = UUIDUtil.getLowerCaseUUID();
      ClientInfo build = ClientInfo.builder().clientSecret(clientSecret).comment(comment).build();
      clientInfoMapper.insertNewClientAddId(build);
      authConfiguration.setComment(comment);
      authConfiguration.setClientId(build.getClientId());
      authConfiguration.setClientSecret(clientSecret);
      return authConfiguration;
   }
   @Override
   public Set<String> getScopeSupportApiList(String scope, String clientId)  {
      ScopeSupportApiListAccess access = getScopeSupportApiListFromRedis(scope);
      if (access != null) {
         logger.info("get scope support list from cache");
         return access.getApiList();
      } else {
         access = getScopeSupportApiListFromMysql(scope, clientId);
         if (access != null) {
            setScopeSupportApiList2Redis(access);
            return access.getApiList();
         } else {
            return null;
         }
      }
   }
   @Override
   public void addJwk(JWKInfo jwkInfo)  {
      JwkInfo jwkInfobyMapper = new JwkInfo();
      BeanUtils.copyProperties(jwkInfo, jwkInfobyMapper);
      jwkInfoMapper.insertSelective(jwkInfobyMapper);
   }
   @Override
   public JwksInfo getJwk()  {
      JwksInfo access = getJwkFromRedis();
      if (access != null) {
         logger.info("get jwks from cache");
         return access;
      } else {
         access = getJwkFromMysql();
         if (access.getJwks().size() > 0) {
            setJwk2Redis(access);
         }

         return access;
      }
   }

   private JwksInfo getJwkFromRedis()  {
      try {
         Object result = redisTemplate.opsForValue().get(getJwksInfoKey());
         if (result != null) {
            return (JwksInfo)result;
         }
      } catch (Exception var2) {
         logger.info("getJwkFromRedis error:" + var2.getMessage());
      }

      return null;
   }

   private void setJwk2Redis(JwksInfo jwksInfo)  {
      try {
         redisTemplate.opsForValue().set(getJwksInfoKey(), jwksInfo, REDIS_TIMEOUT, REDIS_TIMEOUT_UNIT);
      } catch (Exception var3) {
         logger.info("setJwk2Redis error:" + var3.getMessage());
      }

   }

   private JwksInfo getJwkFromMysql()  {
      List<JwkInfo> jwkInfos = jwkInfoMapper.selectAllJwk();
      List<JWKInfo> jwksInfoArrayList = new ArrayList();

      for(int i = 0; i < jwkInfos.size(); ++i) {
         JWKInfo jwkInfo = new JWKInfo();
         BeanUtils.copyProperties(jwkInfos.get(i), jwkInfo);
         jwksInfoArrayList.add(jwkInfo);
      }

      return new JwksInfo(jwksInfoArrayList);
   }

   private String getJwksInfoKey() {
      return "auth.jwks";
   }
   @Override
   public void addScopeSupportApiList(ScopeSupportApiListAccess access)  {
      setScopeSupportApiList2Mysql(access);
      setScopeSupportApiList2Redis(access);
   }
   @Override
   public AuthConfiguration getClientInfo(String clientId)  {
      AuthConfiguration access = getClientInfoFromRedis(clientId);
      if (access != null) {
         logger.info("get client info from cache");
         return access;
      } else {
         access = getClientInfoFromMysql(clientId);
         if (access != null) {
            setClientInfo2Redis(access);
            return access;
         } else {
            return null;
         }
      }
   }

   private String setToString(Set<String> input) {
      Iterator<String> iterator = input.iterator();
      StringBuilder output = new StringBuilder();

      while(iterator.hasNext()) {
         output.append((String)iterator.next()).append("|");
      }

      return output.toString();
   }

   public Set<String> stringToSet(String input) {
      Set<String> output = new HashSet();
      if (input != null && !input.isEmpty()) {
         String[] strings = input.split("\\|");

         for(int i = 0; i < strings.length; ++i) {
            output.add(strings[i]);
         }

         return output;
      } else {
         return output;
      }
   }
   @Override
   public void setClientScope(String clientId, Set<String> scopes)  {
      Iterator iterator = scopes.iterator();

      while(iterator.hasNext()) {
         String next = (String)iterator.next();
         ScopeApilistInfo scopeApilistInfo = scopeApilistInfoMapper.selectByScope(next);
         BindClientScope bindClientScope;
         if (scopeApilistInfo == null) {
            scopeApilistInfo = new ScopeApilistInfo();
            scopeApilistInfo.setScope(next);
            scopeApilistInfoMapper.insertAndReturnId(scopeApilistInfo);
            bindClientScope = new BindClientScope();
            bindClientScope.setScopeApilistId(scopeApilistInfo.getId());
            bindClientScope.setClientId(Integer.parseInt(clientId));
            bindClientScopeMapper.insertSelective(bindClientScope);
         } else {
            bindClientScope = new BindClientScope();
            bindClientScope.setClientId(Integer.parseInt(clientId));
            bindClientScope.setScopeApilistId(scopeApilistInfo.getId());
            if (bindClientScopeMapper.selectByClientIdAndScope(bindClientScope) == null) {
               bindClientScopeMapper.insertSelective(bindClientScope);
            }
         }
      }

   }
   @Override
   public List<ScopeSupportApiListAccess> getAllScopeInfoFromDB()  {
      try {
         List<ScopeApilistInfo> scopeApilistInfos = scopeApilistInfoMapper.selectAllScope();
         List collect = (List)scopeApilistInfos.stream().map((temp) -> {
            ScopeSupportApiListAccess info = new ScopeSupportApiListAccess();
            info.setScope(temp.getScope());
            info.setApiList(stringToSet(temp.getApiList()));
            info.setCreateTime(temp.getCreateTime());
            info.setUpdateTime(temp.getUpdateTime());
            return info;
         }).collect(Collectors.toList());
         return collect;
      } catch (Exception var3) {
         throw new ApiException("getAllScopeInfoFromDB error:" + var3.getMessage());
      }
   }

   private AuthConfiguration getClientInfoFromRedis(String clientId)  {
      try {
         Object result = redisTemplate.opsForValue().get(getClientInfoKey(clientId));
         if (result != null) {
            return (AuthConfiguration)result;
         }
      } catch (Exception var3) {
         logger.info("getClientInfoFromRedis error:" + var3.getMessage());
      }

      return null;
   }

   private void setClientInfo2Redis(AuthConfiguration access) {
      try {
         redisTemplate.opsForValue().set(getClientInfoKey(String.valueOf(access.getClientId())), access, REDIS_TIMEOUT, REDIS_TIMEOUT_UNIT);
      } catch (Exception var3) {
         logger.info("setClientInfo2Redis error:" + var3.getMessage());
      }

   }

   private String getClientInfoKey(String clientId) {
      return "auth.client." + clientId;
   }

   private AuthConfiguration getClientInfoFromMysql(String clientId)  {
      ClientInfo clientInfo = clientInfoMapper.selectByPrimaryKey(Integer.parseInt(clientId));
      AuthConfiguration result = new AuthConfiguration();
      result.setClientId(clientInfo.getClientId());
      result.setClientSecret(clientInfo.getClientSecret());
      result.setComment(clientInfo.getComment());
      result.setCreateTime(clientInfo.getCreateTime());
      result.setUpdateTime(clientInfo.getUpdateTime());
      List<BindClientScope> bindClientScopes = bindClientScopeMapper.selectByClientId(Integer.parseInt(clientId));
      if (bindClientScopes != null && bindClientScopes.size() != 0) {
         List<ScopeApilistInfo> scopeApilistInfos = scopeApilistInfoMapper.selectScopeByIds(bindClientScopes);
         Set<String> collect = (Set)scopeApilistInfos.stream().map((temp) -> {
            return temp.getScope();
         }).collect(Collectors.toSet());
         result.setScopes(collect);
         return result;
      } else {
         return result;
      }
   }

   private void setScopeSupportApiList2Mysql(ScopeSupportApiListAccess access)  {
      ScopeApilistInfo scopeApilistInfo = scopeApilistInfoMapper.selectByScope(access.getScope());
      if (scopeApilistInfo == null) {
         scopeApilistInfo = new ScopeApilistInfo();
         scopeApilistInfo.setScope(access.getScope());
         scopeApilistInfo.setApiList(setToString(access.getApiList()));
         scopeApilistInfoMapper.insertSelective(scopeApilistInfo);
      } else {
         Set<String> apiList = access.getApiList();
         Set<String> strings = stringToSet(scopeApilistInfo.getApiList());
         strings.addAll(apiList);
         scopeApilistInfo.setApiList(setToString(strings));
         scopeApilistInfoMapper.updateByScope(scopeApilistInfo);
      }

   }

   private ScopeSupportApiListAccess getScopeSupportApiListFromMysql(String scope, String clientId)  {
      List<BindClientScope> bindClientScopes = bindClientScopeMapper.selectByClientId(Integer.parseInt(clientId));
      if (scope.contains("|")) {
         Set<String> scopes = stringToSet(scope);
         Iterator<String> iterator = scopes.iterator();
         HashSet output = new HashSet();

         while(iterator.hasNext()) {
            String scopeIndex = (String)iterator.next();
            ScopeApilistInfo scopeApilistInfos = scopeApilistInfoMapper.selectScopeByIdAndScope(bindClientScopes, scopeIndex);
            if (scopeApilistInfos != null) {
               output.addAll(stringToSet(scopeApilistInfos.getApiList()));
            }
         }

         ScopeSupportApiListAccess result = new ScopeSupportApiListAccess();
         result.setScope(scope);
         result.setApiList(output);
         return result;
      } else {
         ScopeApilistInfo scopeApilistInfos = scopeApilistInfoMapper.selectScopeByIdAndScope(bindClientScopes, scope);
         if (scopeApilistInfos != null) {
            ScopeSupportApiListAccess result = new ScopeSupportApiListAccess();
            result.setScope(scope);
            result.setApiList(stringToSet(scopeApilistInfos.getApiList()));
            return result;
         } else {
            return null;
         }
      }
   }

   private void setScopeSupportApiList2Redis(ScopeSupportApiListAccess access) {
      try {
         redisTemplate.opsForValue().set(getScopeSupportApiListKey(access.getScope()), access, REDIS_TIMEOUT, REDIS_TIMEOUT_UNIT);
      } catch (Exception var3) {
         logger.info("setScopeSupportApiList2Redis error:" + var3.getMessage());
      }

   }

   private ScopeSupportApiListAccess getScopeSupportApiListFromRedis(String scope) {
      try {
         Object result = redisTemplate.opsForValue().get(getScopeSupportApiListKey(scope));
         if (result != null) {
            return (ScopeSupportApiListAccess)result;
         }
      } catch (Exception var3) {
         logger.info("getScopeSupportApiListFromRedis error:" + var3.getMessage());
      }

      return null;
   }

   private String getScopeSupportApiListKey(String scope) {
      return "auth.scope." + scope;
   }

   static {
      REDIS_TIMEOUT_UNIT = TimeUnit.SECONDS;
   }
}
